﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HA.ModFlow.Domain.DomainLayer;
using System.Runtime.Serialization;

namespace HA.Data
{
    [Serializable]
    public class ArealPropertyData:ICloneable
    {
        public ArealPropertyData(List<string> names)
        {
            //this._nPeriods = nPeriods;
            this._rechargeRate = new MultiValue("");
            this._maxETRateV2 = new MultiValue("");
            this._etRateV2 = new MultiValue("");
            this._etExtDepthV2 = new MultiValue("");
            this._rechargeConc = new APRechargeConcentration(names);
            this._startingconcentration = new APStartingConc(names);
        }

        //int _nPeriods;


        APRechargeConcentration _rechargeConc;

        public APRechargeConcentration RechargeConc
        {
            get { return _rechargeConc; }
            set { _rechargeConc = value; }
        }

        MultiValue _rechargeRate;

        public MultiValue RechargeRate
        {
            get { return _rechargeRate; }
            set { _rechargeRate = value; }
        }



        double _hk;

        public double Hk
        {
            get { return _hk; }
            set { _hk = value; }
        }
        double _vk;

        public double Vk
        {
            get { return _vk; }
            set { _vk = value; }
        }
        double _hani;

        public double Hani
        {
            get { return _hani; }
            set { _hani = value; }
        }
        double _vani;

        public double Vani
        {
            get { return _vani; }
            set { _vani = value; }
        }

        double _specStorage;

        public double SpecStorage
        {
            get { return _specStorage; }
            set { _specStorage = value; }
        }
        double _specYield;

        public double SpecYield
        {
            get { return _specYield; }
            set { _specYield = value; }
        }


        double _gridTopElev;

        public double GridTopElev
        {
            get { return _gridTopElev; }
            set { _gridTopElev = value; }
        }


        double _gridBotElev;

        public double GridBotElev
        {
            get { return _gridBotElev; }
            set { _gridBotElev = value; }
        }

        double _wetdryFlag;

        public double WetdryFlag
        {
            get { return _wetdryFlag; }
            set { _wetdryFlag = value; }
        }


        double _maxETRate;

        public double MaxETRate
        {
            get { return _maxETRate; }
            set { _maxETRate = value; }
        }

        MultiValue _maxETRateV2;

        public MultiValue MaxETRateV2
        {
            get { return _maxETRateV2; }
            set { _maxETRateV2 = value; }
        }


        double _etRate;


        /// <summary>
        /// 高程值 同etelev
        /// </summary>
        public double EtRate
        {
            get { return _etRate; }
            set { _etRate = value; }
        }

        MultiValue _etRateV2;

        public MultiValue EtRateV2
        {
            get { return _etRateV2; }
            set { _etRateV2 = value; }
        }


        double _etExtDepth;

        public double EtExtDepth
        {
            get { return _etExtDepth; }
            set { _etExtDepth = value; }
        }

        MultiValue _etExtDepthV2;

        public MultiValue EtExtDepthV2
        {
            get { return _etExtDepthV2; }
            set { _etExtDepthV2 = value; }
        }

        double _porosity;

        public double Porosity
        {
            get { return _porosity; }
            set { _porosity = value; }
        }




        ///bcf相关的
        ///

        double _transmissity;

        public double Transmissity
        {
            get { return _transmissity; }
            set { _transmissity = value; }
        }



        double _leakance;

        public double Leakance
        {
            get { return _leakance; }
            set { _leakance = value; }
        }


        double _primaryStorage;

        public double PrimaryStorage
        {
            get { return _primaryStorage; }
            set { _primaryStorage = value; }
        }

        double _secondStorage;

        public double SecondStorage
        {
            get { return _secondStorage; }
            set { _secondStorage = value; }
        }

        double _longdispersity;

        public double Longdispersity
        {
            get { return _longdispersity; }
            set { _longdispersity = value; }
        }

        double _bulkdensity;

        public double Bulkdensity
        {
            get { return _bulkdensity; }
            set { _bulkdensity = value; }
        }
        double _immobileporosity;

        public double Immobileporosity
        {
            get { return _immobileporosity; }
            set { _immobileporosity = value; }
        }
        APStartingConc _startingconcentration;

        public APStartingConc Startingconcentration
        {
            get { return _startingconcentration; }
            set { _startingconcentration = value; }
        }


        protected void assistMapToModFlow(List<double> stressPeriods, List<double> gennerInner, BCDateDataCollection datas)
        {
            if (datas.IsDataConst)
            {
                for (int i = 0; i < stressPeriods.Count; i++)
                {
                    gennerInner[i] = datas.ConstData;
                }

                return;
            }

            List<BCDateData> dataValues = datas.BCDatas;            

            int j = 0;
            //开始按应力期循环
            for (int i = 0; i < stressPeriods.Count; i++)
            {
                //如果设置的时间段未遍历完毕且在应力期内 
                if (j < dataValues.Count)
                {
                    //如果前一个应力期刚好将时间段用完
                    if (i >= 1 && j == dataValues.Count - 1 && stressPeriods[i - 1] >= dataValues[j].EndTime)
                    {
                        break;
                    }
                    //如果该应力期在同一个时间段内
                    if (stressPeriods[i] <= dataValues[j].EndTime)
                    {
                        gennerInner[i] = dataValues[j].Value;
                        if (stressPeriods[i] == dataValues[j].EndTime)
                            j++;
                    }
                    else //该应力期不在同一个时间段内
                    {
                        int start = j;

                        if (dataValues[dataValues.Count - 1].EndTime >= stressPeriods[i])
                        {
                            while (dataValues[j].EndTime < stressPeriods[i])
                            {
                                j++;
                            }
                        }
                        else
                        {
                            j = dataValues.Count - 1;
                        }
                        double sumValue = 0;

                        if (j >= start)
                        {
                            if (j == start)//过滤掉在同一应力期的无效数据
                            {
                                if (i >= 1)
                                {
                                    if (stressPeriods[i - 1] < dataValues[j].Value)
                                    {
                                        gennerInner[i] = (dataValues[j].EndTime - stressPeriods[i - 1]) * dataValues[j].Value / (stressPeriods[i] - stressPeriods[i - 1]);
                                    }
                                }
                                else
                                {
                                    gennerInner[i] = dataValues[j].EndTime * dataValues[j].Value / stressPeriods[i];
                                }
                                break;
                            }

                            if (i > 0)
                                sumValue = (dataValues[start].EndTime - stressPeriods[i - 1]) * dataValues[start].Value;
                            else
                                sumValue = (dataValues[start].EndTime - dataValues[start].StartTime + 1) * dataValues[start].Value;
                            for (int t = start + 1; t < j; t++)
                            {
                                sumValue += (dataValues[t].EndTime - dataValues[t].StartTime + 1) * dataValues[t].Value;
                            }
                            if (j < dataValues.Count - 1)
                                sumValue += (stressPeriods[i] - dataValues[j].StartTime + 1) * dataValues[j].Value;
                            else
                            {

                                sumValue += ((dataValues[j].EndTime > stressPeriods[i] ? stressPeriods[i] : dataValues[j].EndTime) - dataValues[j].StartTime + 1) * dataValues[j].Value;
                            }
                            sumValue /= (i == 0 ? (stressPeriods[i]) : (stressPeriods[i] - stressPeriods[i - 1]));
                            gennerInner[i] = sumValue;
                        }
                    }
                }//end if 设置的时间段未遍历完毕且在应力期内 
                else
                {
                    //终止循环 即剩余应力期数据为默认值0
                    break;
                }
            }
        }
        


        /// <summary>
        /// 根据该类中的数据更新和所绘制的多边形相交的有效单元格的
        /// </summary>
        /// <param name="mf"></param>
        /// <param name="setup"></param>
        /// <param name="ijkList"></param>
        public void MaptoModflow(List<double> stressPeriods, ModFlowData mf, CoverageSetup setup, List<ValueResult> ijkList)
        {
            //foreach (KeyValuePair<MAPArealType,bool>  item in setup.ArealTypes)
            //{



            //}

            //首先做数据的有效性的判断

            // ijkList 存储了和多边形相交的网格体单元格的 I,J,K  注意： 索引号都是从 1 开始的

            if (mf == null || setup == null || ijkList == null)
            {
                return;
            }

            for (int i = 0; i < ijkList.Count; i++)
            {

                ValueResult valueResult = ijkList[i];


                if (setup.ArealTypes[MAPArealType.TOPELVE] == true)
                {
                    //一个单元格的上表面的面单元格中心点的高程值

                    mf.GridData.Elevations[valueResult.K - 1][valueResult.I - 1, valueResult.J - 1] = this._gridTopElev;

                    //this._gridTopElev;
                }

                if (setup.ArealTypes[MAPArealType.BOTELVE] == true)
                {
                    //一个单元格的下表面的面单元格中心点的高程值

                    mf.GridData.Elevations[valueResult.K ][valueResult.I - 1, valueResult.J - 1] = this.GridBotElev;

                    //this._gridBotElev;

                }
                if (setup.ArealTypes[MAPArealType.RECHARGERATE] == true)
                {
                    List<double> valueDatas=new List<double>(stressPeriods.Count);

                    foreach (var sp in stressPeriods)
                    {
                        valueDatas.Add(0);
                    }

                    this.assistMapToModFlow(stressPeriods,valueDatas,this._rechargeRate.DateDatas);

                    for (int j = 0; j < mf.StressPeriods.InnerList.Count; j++)
                    {
                        //mf.SourceSinks.Recharges.Recharge.Periods[j].Flux[valueResult.I - 1, valueResult.J - 1] = this._rechargeRate.Datas[j];
                        mf.SourceSinks.Recharges.Recharge.Periods[j].Flux[valueResult.I - 1, valueResult.J - 1] = valueDatas[j];
                        
                    }
                    

                    //this._rechargeRate;

                }
                if (setup.ArealTypes[MAPArealType.HORIZONTALK] == true)
                {
                    mf.FlowData.Hk.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1]=this.Hk;

                    //mf.InnerData.Layers[valueResult.K - 1].HK[valueResult.I - 1, valueResult.J - 1] = this._hk;

                    //this._hk;

                }
                if (setup.ArealTypes[MAPArealType.VERTICLEK] == true)
                {
                    mf.FlowData.LpfData.Vka.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._vk;

                  

                    //this._vk;
                }
                if (setup.ArealTypes[MAPArealType.HORIZONTALANIS] == true)
                {

                    mf.FlowData.LpfData.Hani.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._hani;


                 

                    //this._hani;
                }
                if (setup.ArealTypes[MAPArealType.VERTICLEANIS] == true)
                {

                    mf.FlowData.LpfData.Vka.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._vani;


                    //this._vani;
                }
                if (setup.ArealTypes[MAPArealType.SPECIFICSTORAGE] == true)
                {

                    mf.FlowData.LpfData.Ss.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._specStorage;


                    //this._specStorage;
                }
                if (setup.ArealTypes[MAPArealType.SPECIFICYIELD] == true)
                {

                    mf.FlowData.LpfData.Sy.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._specYield;

                    //mf.InnerData.Layers[valueResult.K - 1].LpfLayer.Sy[valueResult.I - 1, valueResult.J - 1] = this._specYield;


                    //this._specYield;
                }

                if (setup.ArealTypes[MAPArealType.WETDRYFALG] == true)
                {
                    mf.FlowData.WetDry.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._wetdryFlag;

                    //mf.InnerData.Layers[valueResult.K - 1].LpfLayer.WETDRY[valueResult.I - 1, valueResult.J - 1] = this._wetdryFlag;


                    //this._wetdryFlag;
                }

                if (setup.ArealTypes[MAPArealType.MAXETRATE] == true)
                {
                    List<double> valueDatas = new List<double>(stressPeriods.Count);

                    foreach (var sp in stressPeriods)
                    {
                        valueDatas.Add(0);
                    }

                    this.assistMapToModFlow(stressPeriods, valueDatas, this._maxETRateV2.DateDatas);

                    for (int j = 0; j < mf.StressPeriods.InnerList.Count; j++)
                    {
                        mf.SourceSinks.Evts.EVT.Periods[j].MaxETRate[valueResult.I - 1, valueResult.J - 1] = valueDatas[j];


                    }

                   
                }
                if (setup.ArealTypes[MAPArealType.ETELEV] == true)
                {
                    List<double> valueDatas = new List<double>(stressPeriods.Count);

                    foreach (var sp in stressPeriods)
                    {
                        valueDatas.Add(0);
                    }

                    this.assistMapToModFlow(stressPeriods, valueDatas, this._etRateV2.DateDatas);

                    for (int j = 0; j < mf.StressPeriods.InnerList.Count; j++)
                    {
                        mf.SourceSinks.Evts.EVT.Periods[j].Elevation[valueResult.I - 1, valueResult.J - 1] = valueDatas[j];


                    }

                    
                }
                if (setup.ArealTypes[MAPArealType.ETEXTINCTIONDEPTH] == true)
                {
                    List<double> valueDatas = new List<double>(stressPeriods.Count);

                    foreach (var sp in stressPeriods)
                    {
                        valueDatas.Add(0);
                    }

                    this.assistMapToModFlow(stressPeriods, valueDatas, this._etExtDepthV2.DateDatas);

                    for (int j = 0; j < mf.StressPeriods.InnerList.Count; j++)
                    {
                        mf.SourceSinks.Evts.EVT.Periods[j].ExtinctDepth[valueResult.I - 1, valueResult.J - 1] = valueDatas[j];


                    }

                   
                }
                if (setup.ArealTypes[MAPArealType.POROSITY] == true)
                {

                    //mt3d的对应项,暂时不写，需该接口

                    

                    //this._porosity;
                }





                if (setup.ArealTypes[MAPArealType.TRANSMISSITY] == true)
                {

                    mf.FlowData.BcfData.Transmissivity.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._transmissity;

                    //this._specStorage;
                }
                if (setup.ArealTypes[MAPArealType.LEAKANCE] == true)
                {


                    mf.FlowData.BcfData.Leakance.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._leakance; 

                    //mf.InnerData.Layers[valueResult.K - 1].BcfLayer.LEAKANCE[valueResult.I - 1, valueResult.J - 1] = this._leakance;


                    //this._specYield;
                }


                if (setup.ArealTypes[MAPArealType.PrimaryStorage] == true)
                {

                    mf.FlowData.BcfData.PrimaryStorage.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._primaryStorage; 


                    //mf.InnerData.Layers[valueResult.K - 1].BcfLayer.SF1[valueResult.I - 1, valueResult.J - 1] = this._primaryStorage;

                    //this._specStorage;
                }
                if (setup.ArealTypes[MAPArealType.SecondaryStorage] == true)
                {

                    mf.FlowData.BcfData.SecondaryStorage.Datas[valueResult.I - 1, valueResult.J - 1, valueResult.K - 1] = this._secondStorage; 


                    //mf.InnerData.Layers[valueResult.K - 1].BcfLayer.SF2[valueResult.I - 1, valueResult.J - 1] = this._secondStorage;


                    //this._specYield;
                }





                valueResult = null;


            }//for循环结束



        }

        public void MapToMt3dms(List<double> stressPeriods, CoverageSetup setup, List<ValueResult> ijkList, HA.MT3DMS.DomainLayer.MT3DMSData data)
        {

            List<double[,]> porosity = data.BasicTransport.Grid.GetPorosity();
            for (int i = 0; i < ijkList.Count; i++)
            {

                ValueResult valueResult = ijkList[i];

                if (setup.ArealTypes[MAPArealType.IMMOBILEPOROSITY] == true)
                {
                    //E2B   PRSITY2 化学反应子程序包(Chemical Reaction Package)
                    data.ChemicalReaction.Porosity2[valueResult.K - 1][valueResult.I - 1, valueResult.J - 1] = this.Immobileporosity;
                }

                if (setup.ArealTypes[MAPArealType.STARTINGCONCENTRATION] == true)
                {
                    //初始浓度(单位,MM-1). E2C 基本包BTN
                    for (int j = 0; j < data.BasicTransport.SpeciesCollecion.Species.Count; j++)
                    {
                        data.BasicTransport.SpeciesCollecion.Species[j].InitConc[valueResult.K - 1][valueResult.I - 1, valueResult.J - 1] = this._startingconcentration.SpecConc[j];
                    }
                }

                if (setup.ArealTypes[MAPArealType.POROSITY] == true)
                {
                    porosity[valueResult.K - 1][valueResult.I - 1, valueResult.J - 1] = this.Porosity;
                }

                if (setup.ArealTypes[MAPArealType.BULKDENSITY] == true)
                {
                    //化学反应子程序包(Chemical Reaction Package)
                    data.ChemicalReaction.BulkDensity[valueResult.K - 1][valueResult.I - 1, valueResult.J - 1] = this.Bulkdensity;

                }

                if (setup.ArealTypes[MAPArealType.LONGDISPERSITY] == true)
                {

                    //弥散子程序包（Dispersion Package）
                    data.Dispersion.AL[valueResult.K - 1][valueResult.I - 1, valueResult.J - 1] = this.Longdispersity;


                }

            }
            if (setup.ArealTypes[MAPArealType.POROSITY] == true)
            {
                data.BasicTransport.Grid.SetPorosity(porosity);
            }

            if (setup.ArealTypes[MAPArealType.RECHARGECONC])
            {
                

                for (int j = 0; j < this._rechargeConc.SpecConc.Count; j++)
                {
                    List<double> valueDatas = new List<double>(stressPeriods.Count);
                    foreach (var sp in stressPeriods)
                    {
                        valueDatas.Add(0);
                    }

                    this.assistMapToModFlow(stressPeriods, valueDatas, this._rechargeConc.SpecConc[j].DateDatas);

                    for (int k = 0; k < stressPeriods.Count; k++)
                    {
                        MT3DMS.DomainLayer.SPPolygonConc sppc = data.SourceSinkMixing.RechargeSpConc[j][k];
                        //double conc = valueDatas[k];

                        for (int i = 0; i < ijkList.Count; i++)
                        {
                            sppc.Conc[ijkList[i].I - 1, ijkList[i].J - 1] = valueDatas[k];
                        }
                    }
                }
            }

        }




        public object Clone()
        {
            ArealPropertyData apData = (ArealPropertyData)this.MemberwiseClone();

            apData._rechargeRate = (MultiValue)this._rechargeRate.Clone();
            apData._rechargeConc = (APRechargeConcentration)this._rechargeConc.Clone();
            apData._startingconcentration = (APStartingConc)this._startingconcentration.Clone();

            return apData;
        }

        #region 序列化

        [OnDeserialized]
        void OnDeserialized(StreamingContext context)
        {
            ////三者为同时添加 判断其中一个就好
            //if (this._maxETRateV2 == null || this._etExtDepthV2 == null || this._etRateV2 == null)
            //{
            //    this._nPeriods = this._rechargeRate.NPeriods;
            //    this._maxETRateV2 = new MultiValue(this._nPeriods, "");
            //    this._etRateV2 = new MultiValue(this._nPeriods, "");
            //    this._etExtDepthV2 = new MultiValue(this._nPeriods, "");
            //}
        }

        #endregion
    }


    [Serializable]
    public class APRechargeConcentration : ICloneable
    {
        public APRechargeConcentration(List<string> names)
        {
            //this._nPeriods = nPeriods;

            foreach (string name in names)
            {

                MultiValue mv = new MultiValue(name);

                this._specConc.Add(mv);


            }
        }

        //int _nPeriods = 1;

        //public int NPeriods
        //{
        //    get { return _nPeriods; }
        //    set
        //    {
        //        if (this._nPeriods != value)
        //        {
        //            _nPeriods = value;

        //            this.OnNPeriodsChanged();
        //        }
        //    }
        //}

        List<MultiValue> _specConc = new List<MultiValue>();

        public List<MultiValue> SpecConc
        {
            get { return _specConc; }
            set { _specConc = value; }
        }



        #region 方法
        

        //public void OnNPeriodsChanged()
        //{
        //    foreach (MultiValue item in this._specConc)
        //    {
        //        item.NPeriods = this.NPeriods;

        //    }
        //}

        public void OnSpeListChanged(List<string> lst)
        {
            //写一个算法，要保证顺序性
            this._specConc.Clear();
            foreach (string name in lst)
            {
                MultiValue mv = new MultiValue(name);

                this._specConc.Add(mv);

            }
        }

        #endregion

        #region 克隆方法
        

        public object Clone()
        {
            APRechargeConcentration obj = (APRechargeConcentration)this.MemberwiseClone();
            obj.SpecConc = new List<MultiValue>();
            for (int i = 0; i < this.SpecConc.Count; i++)
            {
                obj.SpecConc.Add((MultiValue)this.SpecConc[i].Clone());
            }

            return obj;
        }


        #endregion

    }

    [Serializable]
    public class APStartingConc : ICloneable
    {
        public APStartingConc(List<string> names)
        {
            foreach (string name in names)
            {
                this._names.Add(name);
                this._specConc.Add(0);
            }
        }


        List<double> _specConc = new List<double>();

        public List<double> SpecConc
        {
            get { return _specConc; }
            set { _specConc = value; }
        }

        List<string> _names = new List<string>();

        public List<string> SpecNames
        {
            get { return _names; }
            set { _names = value; }
        }

        #region 方法
        
        public void OnSpeListChanged(List<string> lst)
        {
            //写一个算法，要保证顺序性
            this._specConc.Clear();
            this._names.Clear();
            foreach (string name in lst)
            {
                this._names.Add(name);
                this._specConc.Add(0);
            }
        }

        #endregion

        #region 克隆方法
        

        public object Clone()
        {
            APStartingConc obj = (APStartingConc)this.MemberwiseClone();
            obj._specConc = new List<double>();

            obj._specConc.AddRange(this._specConc);

            return obj;
        }


        #endregion
    }

}
